﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using WFExtended.Framework.ServiceModel;

namespace WFExtended.Twitter
{
    /// <summary>
    /// Twitter Api Client
    /// </summary>
    public class TwitterClient : IDisposable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterClient"/> class.
        /// </summary>
        /// <param name="useSsl">if set to <c>true</c> [use SSL].</param>
        /// <param name="consumerKey">The consumer key.</param>
        /// <param name="consumerSecret">The consumer secret.</param>
        /// <param name="applicationAccessToken">The application access token.</param>
        /// <param name="applicationAccessTokenSecret">The application access token secret.</param>
        public TwitterClient(bool useSsl, string consumerKey, string consumerSecret, string applicationAccessToken, string applicationAccessTokenSecret)
            : this(useSsl, OAuthTokens.Create(consumerKey, consumerSecret, applicationAccessToken, applicationAccessTokenSecret))
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterClient"/> class.
        /// </summary>
        /// <param name="consumerKey">The consumer key.</param>
        /// <param name="consumerSecret">The consumer secret.</param>
        /// <param name="applicationAccessToken">The application access token.</param>
        /// <param name="applicationAccessTokenSecret">The application access token secret.</param>
        public TwitterClient(string consumerKey, string consumerSecret, string applicationAccessToken, string applicationAccessTokenSecret)
            :this(OAuthTokens.Create(consumerKey, consumerSecret, applicationAccessToken, applicationAccessTokenSecret))
        {}

        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterClient"/> class.
        /// </summary>
        /// <param name="tokens">The OAuth tokens.</param>
        public TwitterClient(OAuthTokens tokens)
            : this(true, tokens)
        { }


        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterClient"/> class.
        /// </summary>
        /// <param name="useSsl">if set to <c>true</c> [use SSL].</param>
        /// <param name="tokens">The OAuth tokens.</param>
        public TwitterClient(bool useSsl, OAuthTokens tokens)
        {
            _useSsl = useSsl;
            _tokens = tokens;
        }

        private bool _useSsl;

        private OAuthTokens _tokens;

        private WcfProxy<ITwitterApi> _proxy = null;

        /// <summary>
        /// Access to the Twitter Api
        /// </summary>
        /// <value>
        /// Twitter Api
        /// </value>
        public ITwitterApi Api
        {
            get
            {
                if (_proxy == null)
                {
                    _proxy = new WcfProxy<ITwitterApi>(0, new TimeSpan(0, 0, 1));
                    _proxy.ChannelType = ChannelType.Web;
                    _proxy.EndPoint = GetTwitterEndpoint(_useSsl,_tokens);
                }

                return _proxy.Client;
            }
        }

        /// <summary>
        /// Sets the user context.
        /// </summary>
        /// <param name="userAccessToken">The user access token.</param>
        /// <param name="userAccessTokenSecret">The user access token secret.</param>
        public void SetUserContext(string userAccessToken, string userAccessTokenSecret)
        {
            _tokens.UserAccessToken = userAccessToken;
            _tokens.UserAccessTokenSecret = userAccessTokenSecret;
        }

        /// <summary>
        /// Clears the user context.
        /// </summary>
        public void ClearUserContext()
        {
            _tokens.UserAccessToken = String.Empty;
            _tokens.UserAccessTokenSecret = String.Empty;
        }

        internal static ServiceEndpoint GetTwitterEndpoint(bool useSsl, OAuthTokens tokens)
        {
            Uri apiAddress = (useSsl) 
                ? new Uri("https://api.twitter.com/1.1/")  : new Uri("http://api.twitter.com/1.1/");
            ServiceEndpoint endpoint = new ServiceEndpoint(
                 ContractDescription.GetContract(typeof(ITwitterApi)),
                 new WebHttpBinding()
                 {
                     Security = new WebHttpSecurity()
                     {
                         Mode = (useSsl) ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None
                     },
                     MaxReceivedMessageSize = 65536000,
                     ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
                     {
                         MaxStringContentLength = 6553600
                     }
                 },
                 new EndpointAddress(apiAddress));

            endpoint.EndpointBehaviors.Add(new OAuthBehavior(tokens));
            endpoint.EndpointBehaviors.Add(new ParameterEncodingBehavior());
            ServiceErrorNotifier.AddObserver(new TwitterExceptionObserver());

            return endpoint;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (_proxy != null)
                _proxy.Dispose();

            _proxy = null;
        }
    }
}
